package org.http;

import com.alibaba.fastjson.JSONObject;
import org.http.exp.TinyException;
import org.http.response.ResponseHeaders;
import org.http.response.StatusCodeEnum;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Optional;

/**
 * @author andy
 */
public class RequestHandler implements Runnable {
    SelectionKey selectionKey;
    RequestHandler(SelectionKey selectionKey){
        this.selectionKey = selectionKey;
    }
    @Override
    public void run() {
        try {
            handleRequest();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理请求，将请求封装成request
     */
    private void handleRequest() throws IOException {

        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        ByteBuffer buffer = ByteBuffer.allocate(Const.DEFAULT_BUFFER_SIZE);
        socketChannel.read(buffer);

        buffer.flip();
        byte[] bytes = new byte[buffer.limit()];
        buffer.get(bytes);
        String headerStr = new String(bytes);
        System.out.println(headerStr);
        try {
            HandleHeader hh = new HandleHeader();
            Headers headers = hh.parseHeader(headerStr);
            selectionKey.attach(Optional.of(headers));
            handleResponse();
        } catch (TinyException e) {
            selectionKey.attach(Optional.empty());
        }

    }
    /**
     * 处理请求,将请求封装成response
     */
    private void handleResponse() throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        Optional<Headers> op = (Optional<Headers>) selectionKey.attachment();

        try {
            // 处理请求失败，返回 400 错误
            if (op.isEmpty()) {
                handleResResult(socketChannel, 400);
                socketChannel.close();
                return;
            }
            Headers headers = op.get();
            if (headers.getPath().startsWith("/meta")) {
                handleResResult(socketChannel, 403);
                socketChannel.close();
                return;
            }
            if(headers.getPath().startsWith("/api")){
                handleResResult(socketChannel, 200);
            }else{
                handleResResult(socketChannel, 404);
            }
        } catch (Exception ex){
            handleResResult(socketChannel, 500);
            socketChannel.close();
        } finally {
            socketChannel.close();
        }
    }


    private void handleResResult(SocketChannel channel, int statusCode) throws IOException {
        ResponseHeaders headers = new ResponseHeaders(statusCode);
        headers.setContentType("text/html");
        headers.setCode(statusCode);





        String content = "";


        switch (statusCode){
            case 200:

                Student stu = new Student();
                stu.setAddress("测试");
                stu.setName("qt");
                stu.setAge(18);

                content = JSONObject.toJSONString(stu);

                break;
            case 400:
            case 403:
            case 404:
            case 500:
                ResponseError responseError = new ResponseError();
                responseError.setCode(statusCode);
                responseError.setMsg(StatusCodeEnum.queryPhrase(statusCode));
                content = JSONObject.toJSONString(responseError);
                break;
            default:
                content = "Default: " + statusCode;
                break;
        }

        ByteBuffer bodyBuffer = write(content);
        ByteBuffer headerBuffer = write(headers.toHeaderString());
        channel.write(new ByteBuffer[]{headerBuffer, bodyBuffer});
        headerBuffer.flip();
    }


    /**
     * 将数据返回回去
     * @param content 写入内容
     * @return ByteBuffer
     * @throws IOException ex
     */
    private ByteBuffer write(String content) throws IOException {
        Charset charset = Charset.forName(Const.encoding);
        CharsetEncoder encoder = charset.newEncoder();
        CharBuffer charBuffer = CharBuffer.allocate(content.length());
        charBuffer.put(content);
        charBuffer.flip();
        return encoder.encode(charBuffer);
    }
}
